package org.manon.json.asm;

import java.io.FileOutputStream;

import org.manon.json.JSONException;
import org.manon.json.JSONFactory;
import org.manon.json.SerializerProvider;
import org.manon.json.io.Deserializer;
import org.manon.json.io.Serializer;
import org.manon.json.meta.Entity;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
public final class ASMClassFactory {

	private final ASMClassLoader _classLoader = new ASMClassLoader();
	
	public final Boolean ENABLED_DEBUG = true; //Boolean.getBoolean("manon-json-debug");
	
	public ASMClassFactory(){}

	public void registerSerializer(Entity entity, byte[] bytecode) {
		if (ENABLED_DEBUG) {
			dump(entity.getClassNameForSerializer(),bytecode);	
		}
		_classLoader.defineClass(entity.getClassNameForSerializer(),bytecode);
	}
	
	public void registerDeserializer(Entity entity, byte[] bytecode) {
		if (ENABLED_DEBUG) {
			dump(entity.getClassNameForDeserializer(),bytecode);	
		}
		_classLoader.defineClass(entity.getClassNameForDeserializer(),bytecode);
	}
	
	public void registerInnerClasses(String className, byte[] bytecode) {
		if (ENABLED_DEBUG) {
			dump(className,bytecode);	
		}
		_classLoader.defineClass(className,bytecode);
	}
	
	@SuppressWarnings("unchecked")
	public <T> Serializer<T> newSerializerInstance(Entity entity,JSONFactory factory) {
		
		Class<?> classToInstantiate;
		
		if (entity.getCustomSerializer() != null) {
			classToInstantiate = (Class<T>) entity.getCustomSerializer();
		} else {
			try {
				classToInstantiate = _classLoader.loadClass(entity.getClassNameForSerializer());
			} catch (ClassNotFoundException cause) {
				throw new JSONException("Failed to load class serializer for entity [" + entity + "]",cause);
			}
		}
		
		try {
			return (Serializer<T>) classToInstantiate.getConstructor(SerializerProvider.class).newInstance(factory);
		} catch (Exception cause) {
			throw new JSONException("Failed to instantiate custom serializer for entity [" + entity + "]",cause);
		}
		
	}
	
	@SuppressWarnings("unchecked")
	public <T> Deserializer<T> newDeserializerInstance(Entity entity) {
		try {
			return  (Deserializer<T>) _classLoader.loadClass(entity.getClassNameForDeserializer()).newInstance();
		} catch (Exception cause) {
			throw new JSONException("Failed to instantiate serializer for entity [" + entity + "]",cause);
		}
	}

	private static void dump(String entity,byte[] content) {
		
		try {
			FileOutputStream fos = new FileOutputStream("r:/dump/"+entity.substring(entity.lastIndexOf('.')+1)+".class");
			fos.write(content);
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	
}